#include "chunk.h"


/*
 *@brief:
 *@para:struct connection *conn: 网络连接;
 *
 *@return value: 
 */
int httpMultiPartWaitForBoundary(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:[%s] line:[%d]", __func__,__LINE__);
		return iRet;
	}
	/*
	 *@description:
	 */
	const char * boundary = NULL;
	const char * boundary_end = NULL;
	char *recvbuf = (char *)conn->recvbuf; 
	struct httpOpt * multipartopt = &(conn->httopt);
	/*
	 *@异常情况1:没有从请求报文中获取到boundary 
	 */
	if( multipartopt->mpStream.boundary == NULL){
		multipartopt->mpStream.state =  HTTP_MULTIPART_STATE_FINALIZE;
		return iRet;
	}
	/*
	 *@异常情况2:
	 */
	if(conn->currDataLen < multipartopt->mpStream.boundaryLen + 2){
		return iRet;
	}

	boundary = strnstr(recvbuf, multipartopt->mpStream.boundary, conn->currDataLen);

	if(boundary  != NULL ){
		boundary_end = (boundary + multipartopt->mpStream.boundaryLen);
		/*
		 *@情况1:
		 */
		if(conn->currDataLen - (boundary_end - recvbuf) < 4){
			return iRet;
		}
		/*
		 *@情况2:
		 */
		if(strncmp(boundary_end, "--\r\n", 4) == 0){
			multipartopt->mpStream.state = HTTP_MULTIPART_STATE_FINALIZE;
			/*
			 *
			 */
		}else{
			multipartopt->mpStream.state = HTTP_MULTIPART_STATE_GET_BOUNDARY;
		}
	}else{
		return RET_ERROR;
	}
	return RET_OK;
}

/*@brief:multipart 处理boundary
 *@para:struct connection *conn:网络连接; 
 *
 *@return value:
 */
int httpMultiPartProcessBoundary(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:[%s] line:[%d]", __func__,__LINE__);
		return iRet;
	}
	int dataSize;
	const char *boundary, *blockBegin;
	char *recvbuf = conn->recvbuf; //接收缓冲区的内容;
	struct httpOpt * multipartopt = &(conn->httpopt);
	int lineLen;
	/*
	 *@
	 */
	boundary = strnstr(recvbuf, multipartopt->mpStream.boundary, conn->currDataLen);
	
	blockBegin = boundary + multipartopt->mpStream.boundaryLen + 2;

	dataSize = conn->currDataLen - (blockBegin - recvbuf);

	while(dataSize > 0 && (lineLen  = getLineLen(blockBegin, dataSize))!=0){
		if(lineLen > (int)sizeof(CONTENT_DISPOSITION) && strcasecmp() == 0){
			struct dynString header;
			header.str = blockBegin + sizeof(CONTENT_DISPOSITION) - 1;
			header.len = lineLen - sizeof(CONTENT_DISPOSITION)  - 1;
			/*
			 *@解析出name 和 filename 
			 */
			httpParseHeaderInternal(&header, "name", &Name);
			httpParseHeaderInternal(&header, "filename", &FileName);

			blockBegin += lineLen;
			dataSize -= lineLen;
			continue;
		}
		if( lineLen == 2 && strncasecmp(blockBegin, "\r\n", 2) == 0){
			if(multipartopt->mpStream.processingPart != 0){
				httpMultipartCallHandler(conn, HTTP_PART_END, NULL, 0);
			}

			if(multipartopt->mpStream.fileName){
				free(multipartopt->mpStream.fileName);

			}
			if(multipartopt->mpStream.varName){
				free(multipartopt->mpStream.varName);
			}
			httpMultipartCallHandler(conn, HTTP_PART_BEGIN, NULL, 0);
			multipartopt->mpStream.state = HTTP_MULTIPART_STATE_WAITING_FOR_CHUNK;
			multipartopt->mpStream.processingPart++; //计数器;
			return RET_OK;
		}
		blockBegin += lineLen;
	}

	multipartopt->mpStream.state = HTTP_MULTIPART_STATE_WAITING_FOR_BOUNDARY;
	return RET_ERROR;
}


/*
 *@brief:上传操作
 *@para: struct connection *conn:
 *		 int state 当前的状态;
 *	     struct httpMultiPart *part:
 */
int httpUpload(struct connection *conn, int state, struct httpMultiPart *part){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:%s  line:%d\n", __func__, __LINE__);
		return iRet; 
	}
	struct fileWriterData *fileData = (struct fileWriterData *)conn->userData;
	struct httpMultiPart *mp = part;
	switch(state){
		case HTTP_PART_BEGIN:
			{
				/*
				 *@新建一个文件 
				 */
				fileData = (struct fileWriterData *)malloc(sizeof(struct fileWriterData));
				if(!fileData){
					fileData->fp = fopen("./test.log", "a+");
					fileData->bytesWritten = 0; //
					if( fileData->fp == NULL ){
						conn->currDataLen += sprintf(conn->sendbuf, "%s", "HTTP/1.1 500 Failed to open a file\r\n" 
								"Content-Length: 0\r\n\r\n");
						conn->state = SEND_RESPONSE; //发送状态;
						free(fileData);
						return 
					}
					conn->userData = (void *)fileData;
				}
				break;
			}
		case HTTP_PART_DATA:
			{	
				if(fwrite(mp->data.p , 1, mp->data.len, fileData->fp) != mp->data.len){
					conn->currDataLen += sprintf(conn->sendbuf, "%s", "HTTP/1.1 500 Failed to open a file\r\n" 
								"Content-Length: 0\r\n\r\n");
					conn->state = SEND_RESPONSE;
					return;
				}
				fileData->bytesWritten += mp->data.len;
				break;
			}
		case HTTP_PART_END:
			{
				conn->currDataLen+=sprintf(conn->recvbuf, "HTTP/1.1 200 OK\r\n" 
					 "Content-Type: text/plain\r\n"
					 "Connection: close\r\n\r\n"
					 "Written %ld of POST data to file\n\n", (long)ftell(fileData->fp));
			 		 conn->state = SEND_RESPONSE;
					 fclose(fileData->fp); //关闭文件流;
					 free(fileData);
					 conn->userData = NULL;
					 break;
			}
	}
	return RET_OK;
}



/*
 *@brief:
 *@para:struct connection *conn: 网络连接;
 *
 *
 *@return value:
 */
int httpMultiPartContinueWaitForChunk(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:[%s] line:[%d]", __func__,__LINE__);
		return iRet;
	}
	char *recvbuf = conn->recvbuf;

	struct httpOpt *multipartopt = &(conn->httpopt);
	const char * boundary;

	if(conn->currDataLen < multipartopt->mpStream.boundary + 6){
		//报文有异常; 缺少boundary;
		return iRet;
	}
	
	boundary = strnstr(recvbuf, multipartopt->mpStream.boundary, conn->currDataLen);
	if(boundary == NULL && multipartopt->mpStream.prevIoLen == 0){
		/*
		 *@情况1：
		 */
		multipartopt->mpStream.prevIoLen = conn->currDataLen; //记录当前的数据长度;
		return iRet;
	}else if(boundary == NULL && (conn->currDataLen > multipartopt->mpStream.prevIoLen + multipartopt->mpStream.boundaryLen + 4)){
		/*
		 *@情况2:
		 */
		multipartopt->mpStream.state = HTTP_MULTIPART_STATE_GET_CHUNK;
		return RET_OK;
	}else if(boundary != NULL){
		int dataSize = (boundary - recvbuf - 4);
		/*
		 *@调用特殊的注册接口;
		 */
		multipartopt->mpStream.prevIoLen = 0;
		multipartopt->mpStream.state = HTTP_MULTIPART_STATE_WAITING_FOR_BOUNDARY;
		return RET_OK;
	}else{
		return iRet;
	}
}

/*
 *@brief:
 *@para:
 *
 *@return value:
 */
int httpMultipartCallHandler(struct connection *conn, int eventtype, char * data, int dataLen){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:%s line:%d\n", __func__, __LINE__);
		return iRet;
	}
	struct httpOpt *multipartopt = &(conn->httpopt);
	struct httpMultiPart  mp;	
	memset(&mp, 0, sizeof(mp));
	mp.varName = multipartopt->mpStream.varName;
	mp.fileName = multipartopt->mpStream.fileName;
	mp.userData = multipartopt->mpStream.userData;
	mp.data.str  =  data;
	mp.data.len = dataLen;
	httpUpload(conn, eventtype, &mp);
	multipartopt->mpStream.userData = mp.userData;
	return RET_OK;
}

/*@brief:
 *@para:
 *
 */
int httpMultiPartGotChunk(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:[%s] line:[%d]", __func__,__LINE__);
		return iRet;
	}
	char *recvbuf = conn->recvbuf;
	struct httpOpt *multipartopt = &(conn->httpopt);
	/*
	 *@
	 */
	httpMultipartCallHandler(conn, HTTP_PART_DATA, recvbuf, multipartopt->mpStream.prevIoLen);
	/*
	 *
	 */
	multipartopt->mpStream.prevIoLen = 0;
	multipartopt->mpStream.state = HTTP_MULTIPART_STATE_WAITING_FOR_CHUNK;
	return RET_OK;
}


/*@brief:
 *@para:
 *
 *
 *@return value:
 */
int httpMultiPartFinalize(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:[%s] line:[%d]", __func__, __LINE__);
		return iRet;
	}
	/*
	 *@获取到multipart的上下文;
	 */
	struct httpOpt * multipartopt = &(conn->httpopt);
	/*
	 *@description:
	 */
	httpMultipartCallHandler(conn, HTTP_MULTIPART_END, NULL, 0);
	/*
	 *@释放对应的资源;
	 */
	if(multipartopt->mpStream.fileName){
		free(multipartopt->mpStream.fileName);
		multipartopt->mpStream.fileName = NULL;
	}
	if(multipartopt->mpStream.varName){
		free(multipartopt->mpStream.varName);
		multipartopt->mpStream.varName = NULL;
	}	

	httpMultipartCallHandler(conn, HTTP_MULTIPART_REQUEST_END, NULL, 0);
	/*
	 *@
	 */
	multipartopt->mpStream.state = HTTP_MULTIPART_STATE_FINISHED;
	return RET_OK;
}


/*@brief:
 *@para:struct connection *conn:
 *		struct http_message *hm
 *@return value: 
 */
int httpMultipartBegin(struct connection *conn, struct httpMessage *hm, int requestLen){
	int iRet = RET_ERROR;
#define BUF_SIZE 100
	if(!conn || !hm || requestLen < 0){
		fprintf(stderr, "[error]get unavaliable args in func:%s line:%d", __func__, __LINE__);
		return iRet;
	}
	struct httpOpt *multipartopt = &(conn->httpopt);
	struct dynString *contentType;
	char *recvbuf = (char *)conn->recvbuf;

	char boundaryBuf[BUF_SIZE] = { '\0' };
	
	char *boundary = boundaryBuf;

	int boundaryLen;

	contentType = getHttpHeader(hm, "Content-Type");
	if(contentType == NULL){
		
		goto failed;
	}

	if(contentType->len < 9 || strncmp(contentType->str, "multipart", 9) != 0){
		
		goto failed;
	}
	
	boundaryLen = httpParseHeader(contentType, "boundary", &boundary, sizeof(boundaryBuf));

	if(boundaryLen == 0){
		/*
		 *@异常情况;
		 */
		goto failed;
	}
	if(multipartopt->mpStream.boundary  != NULL ){
		/*
		 *@异常情况;
		 */
		goto failed;
	}else{
		multipartopt->mpStream.state = HTTP_MULTIPART_STATE_BEGIN;
		multipartopt->mpStream.boundary = strdup(boundary);
		multipartopt->mpStream.boundaryLen = strlen(boundary);
		multipartopt->mpStream.varName = multipartopt->mpStream.fileName = NULL;
		/*
		 *@
		 */
	}
	return RET_OK;
failed:
	if(boundary != boundaryBuf){
		free(boundary);
		boundary = NULL;
	}
	return RET_ERROR;
}





/*@brief:
 *@para:struct connection *conn:
 *
 *@return value:
 */
int httpMultipartContinue(struct connection *conn){
	int iRet = RET_ERROR;
	if(!conn){
		fprintf(stderr, "[error]get unavaliable args in func:%s line:%d\n", __func__, __LINE__);
		return iRet;
	}
	struct httpOpt *multipartopt = &(conn->httpopt);
	while(1){
		/*
		 *@接受数据的状态机;
		 */
		switch(multipartopt->mpStream.state){
			case HTTP_MULTIPART_STATE_BEGIN:
				{
					multipartopt->mpStream.state = HTTP_MULTIPART_STATE_WAITING_FOR_BOUNDARY;
					break;
				}
			case HTTP_MULTIPART_STATE_WAITING_FOR_BOUNDARY:
				{
					if(httpMultiPartWaitForBoundary(conn) == RET_ERROR){
						return;
					}
					break;
				}
			case HTTP_MULTIPART_STATE_GET_BOUNDARY:
				{
					if(httpMultiPartProcessBoundary(conn) == RET_ERROR){
						return;
					}
					break;
				}
			case HTTP_MULTIPART_STATE_WAITING_FOR_CHUNK:
				{
					if(httpMultiPartContinueWaitForChunk(conn) == RET_ERROR){
						return;
					}
					break;
				}
			case HTTP_MULTIPART_STATE_GET_CHUNK:
				{
					if(httpMultiPartGetChunk(conn) == RET_ERROR){
						return;
					}
					break;
				}
			case HTTP_MULTIPART_STATE_FINALIZE:
				{
					if(httpMultiPartFinalize(conn) == RET_ERROR){
						return;
					}
					break;
				}
			case HTTP_MULTIPART_STATE_FINISHED:
				{
					return;
				}
			default:
				return;
		}
	}
}


